package Skeleton;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Stack;

/**
 * A Skeletonhoz irt parancssori logolast es interakciot megvalosito osztaly.
 * 
 * @author Csorvasi Janos
 */

public class SkeletonHelper {
	
	private static int indentLevel = 0;
	private static Stack<Object> objStack = new Stack<Object>();
	
	/**
	 * A meghivott metodus elejere beillesztett hivas jelzi, hogy beleptunk az adott metodusba. 
	 * A hivas hatasara a parancsorra kiir egy sort a hivott metodus megfelelo adataival.
	 * 
	 * @param callee hivott objektum
	 * @param inputParams hivas parameterei (ha vannak)
	 */
	public static void Call(Object callee, Object... inputParams){
		String str = new String();
		StackTraceElement ste = null;
		
		objStack.push(callee);

        for(StackTraceElement item : new Exception().getStackTrace())
            if(!item.getClassName().equals(SkeletonHelper.class.getName()))
            {
                ste = item;
                break;
            }

		str = indent() + "===> #" + callee.hashCode() + "|" + callee.getClass().getSimpleName() + "." + ste.getMethodName() + "(";
		for (int i = 0; i < inputParams.length; i++ ){
			if (i != inputParams.length-1){
				str += getObjectSignature(inputParams[i]) + ", ";
			} else {
				str += getObjectSignature(inputParams[i]);
			}        	
        }
		str += ")";
        System.out.println(str);
        indentLevel++;
	}
	
	/**
	 * A meghivott metodus vegere (kozvetlenul a return ele) beillesztett hivas jelzi, hogy visszaterunk az adott metodusbol. 
	 * A hivas hatasara a parancsorra kiir egy sort a hivott metodus megfelelo adataival.
	 * 
	 * @param rv A hivott metodus sajat visszateresi erteke
	 */
	public static void Return(Object rv){
		String str = new String();
		StackTraceElement ste = null;
		
		indentLevel--;

		Object callee = objStack.pop();
		for(StackTraceElement item : new Exception().getStackTrace())
            if(!item.getClassName().equals(SkeletonHelper.class.getName()))
            {
                ste = item;
                break;
            }
		
		str = indent() + "<=== #" + callee.hashCode() + "|" + callee.getClass().getSimpleName() + "." + ste.getMethodName() + "()";
		if (rv != null)
			str += " = " + getObjectSignature(rv);
		
		System.out.println(str);
    }
	
	/**
	 * Eldontendo kerdes feltevesere szolgalo metodus. A parameterben kapott kerdest kiirja a parancsorra
	 * es egy 'y' vagy egy 'n' karaktert var, aminek megfelelo egy true vagy egy false ertekkel ter vissza
	 * @param msg kiirando kerdes
	 * @return true/false
	 */
	public static boolean askTrueFalse(String msg){
        while (true) {
			System.out.print(indent() + "? " + msg + " ");
			BufferedReader be = new BufferedReader(new InputStreamReader(System.in));
	        try {
	            // beolvassuk a valaszt (kis es nagybetu nem szamit)
	            String s = be.readLine().toLowerCase();
	
	            if(s.equals("n"))
	                return false;
	            else if(s.equals("y"))
	                return true;
	            else
	                // helytelen valasz eseten kivetelt generalunk
	                throw new Exception();
	        } catch (Exception e) {
	            // hiba eseten rossz a valasz
	            System.out.println("Rossz a beirt valasz!");
	            System.out.println("Megengedett karakterek: y = igen/true, n = nem/false");
	            continue;
	        }
        }
	}
	
	/**
	 * Egy komplex toString() metodus. A parameter szignaturajaval ter vissza.
	 * 		
	 * @param o
	 * @return 	Null ertek eseten "null" sztringgel terunk vissza. 
	 * Beepitett java osztaly eseten a sajat toString() metodusat hivjuk.
	 * Sajat objektum eseten pedig a hash koddal es a osztaly nevevel mint sztringgel terunk vissza.
	 */
	public static String getObjectSignature(Object o)
    {
        // A null-t nullk�nt irjuk ki
        if(o == null)
            return "null";
        else
        {
            // az objektum osztalya
            Class<?> c = o.getClass();
            // ha beepitett java osztaly, akkor a sajat kiirasat hasznaljuk
            if(!c.isArray() && c.getPackage().getName().startsWith("java."))
                return o.toString();
            // egyebkent pedig egy egyedi objektumazonositot es az osztalynevet irjuk ki
            else
                return "#"+o.hashCode() + "|" + c.getSimpleName();
        }
    }
	/**
	 * Seged metodus a megfelelo hivasi melyseg jelzesehez
	 * 
	 * @return a melyesgnek megfelelo space karakterek
	 */
	private static String indent(){
		String indent = new String();
		for (int i = 0; i<indentLevel; i++){
			indent += "    ";
		}
		return indent;
	}
}
